/*
 * Copyright (c) 2021 Talkweb Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_gpio.h"
#include "iot_watchdog.h"
#include "iot_pwm.h"

//蜂鸣器PWM端口号
#define HI_PWM_BEEP_PORT IOT_PWM_PORT_PWM0
//蜂鸣频率
#define PWM_BEEP_FREQ (4 * 1000)
//蜂鸣占空比
#define PWM_BEEP_DUTY (50)

// 蜂鸣器开关状态
static int gBeepState = 0;

typedef struct
{
    IotGpioIoName gpioName; //灯的GPIO
    int ioFunc;                //IO hi_io_func_gpio
    IotGpioDir dir;            //GPIO 方向
    IotGpioValue value;        //灯当前值
} TrafficLight;
//三色灯的状态数组，每个值代表某个颜色显示还是不显示
// 当前灯序号
static int gCurrentLightId = 0;
static TrafficLight lights[] = {
    //red
    {IOT_GPIO_IO_GPIO_10,
     IOT_IO_FUNC_GPIO_10_GPIO,
     IOT_GPIO_DIR_OUT,
     IOT_GPIO_VALUE0},
    //GREEN
    {IOT_GPIO_IO_GPIO_11,
     IOT_IO_FUNC_GPIO_11_GPIO,
     IOT_GPIO_DIR_OUT,
     IOT_GPIO_VALUE0},
    //BLUE
    {IOT_GPIO_IO_GPIO_12,
     IOT_IO_FUNC_GPIO_12_GPIO,
     IOT_GPIO_DIR_OUT,
     IOT_GPIO_VALUE0},
    //WHITE
    {IOT_GPIO_IO_GPIO_5,
     IOT_IO_FUNC_GPIO_5_GPIO,
     IOT_GPIO_DIR_OUT,
     IOT_GPIO_VALUE0}};
#define MAX_LIGHTS (sizeof(lights) / sizeof(lights[0]))

/**
 *  按键回调。每按一下，亮某个颜色，其他颜色不亮。同时控制蜂鸣器状态
 * \param   arg 回调参数
 */
static void
OnKeyPressed(char *arg)
{
    (void)arg;

    printf("key pressed c\n");

    //只亮当前灯亮
    for (int i = 0; i < MAX_LIGHTS; i++)
    {
        if (i == gCurrentLightId)
        {
            lights[i].value = IOT_GPIO_VALUE1;
        }
        else
        {
            lights[i].value = IOT_GPIO_VALUE0;
        }
    }
    //按一次键 切换一次当前灯
    gCurrentLightId++;
    if (gCurrentLightId == MAX_LIGHTS)
    {
        gCurrentLightId = 0;
    }

    //开关一次蜂鸣器
    gBeepState = !gBeepState;
}

/**
 * 线程入口
 * \param  arg 线程参数
 *
 */
static void *LightTaskEntry(const char *arg)
{
    int i, j;
    (void)arg;

    // 测试灯功能是否正常
    // 先每个灯闪烁一下，亮2秒灭1秒，2遍
    for (i = 0; i <= 1; i++)
    {
        for (j = 0; j < MAX_LIGHTS; j++)
        {
            IoTGpioSetOutputVal(lights[j].gpioName, IOT_GPIO_VALUE1);
            usleep(200 * 1000);

            IoTGpioSetOutputVal(lights[j].gpioName, IOT_GPIO_VALUE0);
            usleep(100 * 1000);
        }
    }

    //线程任务循环
    while (1)
    {
        // 每个灯的状态输出到GPIO
        for (i = 0; i < MAX_LIGHTS; i++)
        {
            IoTGpioSetOutputVal(lights[i].gpioName, lights[i].value);
        }

        // 根据蜂鸣器状态控制
        if (gBeepState)
        {
            // 第二个参数duty分频系数，第三个参数freq，160M时钟，
            // freq，选择40K，占空达到一半，输出的是4K频率
            IoTPwmStart(HI_PWM_BEEP_PORT, PWM_BEEP_DUTY, PWM_BEEP_FREQ); //(WIFI_IOT_PWM_PORT_PWM0, 20*1000, 40*1000);
        }
        else
        {
            IoTPwmStop(HI_PWM_BEEP_PORT);
        }
    }

    return NULL;
}

// 四色显示+蜂鸣。交通灯板，四色等对应
//red:GPIO10
//GREEN GPIO11
//YELLOW GPIO12
//WHITE GPIO13，
//蜂鸣器GPIO09/PWM0，按键中断GPIO08
static void LightExampleEntry(void)
{
    IoTWatchDogDisable();
    //初始化灯的 GPIO 状态
    for (int i = 0; i < MAX_LIGHTS; i++)
    {
        TrafficLight *l = &lights[i];
        IoTGpioInit(l->gpioName);
        //注册功能
        IoTIoSetFunc(l->gpioName, l->ioFunc);

        //注册io方向
        IoTGpioSetDir(l->gpioName, l->dir);
    }
    //按键处理
    IoTGpioInit(IOT_GPIO_IO_GPIO_8);
    IoTIoSetFunc(IOT_GPIO_IO_GPIO_8, IOT_IO_FUNC_GPIO_8_GPIO);
    //上升
    IoTIoSetPull(IOT_GPIO_IO_GPIO_8, IOT_IO_PULL_UP);

    IoTGpioSetDir(IOT_GPIO_IO_GPIO_8, IOT_GPIO_DIR_IN);
    //注册按键回调
    IoTGpioRegisterIsrFunc(IOT_GPIO_IO_GPIO_8, IOT_INT_TYPE_EDGE, IOT_GPIO_EDGE_RISE_LEVEL_HIGH, OnKeyPressed, NULL);

    //蜂鸣器GPIO09/PWM0
    IoTIoSetFunc(IOT_GPIO_IO_GPIO_9, IOT_IO_FUNC_GPIO_9_PWM0_OUT);
    IoTGpioSetOutputVal(IOT_GPIO_IO_GPIO_9, IOT_GPIO_DIR_OUT);
    // 初始化PWM设备，这里是蜂鸣器
    IoTPwmInit(HI_PWM_BEEP_PORT);

    // 设置线程属性
    osThreadAttr_t attr;
    attr.name = "TrafficTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024;
    attr.priority = osPriorityNormal;

    // 开启线程，执行LED任务。开启线程，避免主线程阻塞
    if (osThreadNew((osThreadFunc_t)LightTaskEntry, NULL, &attr) == NULL)
    {
        printf("TrafficLight thread   Create failed.");
    }
}

SYS_RUN(LightExampleEntry);
